package com.pingan.haofang.searchcloud.api.query.parser.visitor;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;

import com.pingan.haofang.searchcloud.api.matedata.FieldMeta;
import com.pingan.haofang.searchcloud.api.matedata.IndexMeta;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.FunctionFactory;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.SqlNode;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.SqlNodeType;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.sqlnode.ColumnNode;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.sqlnode.TextNode;
import com.pingan.haofang.searchcloud.api.query.parser.dbobject.sqlnode.function.Function;
import com.pingan.haofang.searchcloud.api.query.parser.exception.SqlParseException;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.schema.Column;

/**
 * ClassName: SelectNodeVisitor <br>
 * Function: select节点visitor
 *
 * @author luyi
 * @version 1.0.0
 * @since 1.0.0
 * @date 20150621
 */
public class SelectNodeVisitor extends AbstractExpressionVisitor {

    /**
     * select节点
     */
    private SqlNode selectNode;
    
    private IndexMeta meta;

    private boolean useDistinct;

    public SelectNodeVisitor(IndexMeta meta, boolean useDistinct) {
        this.meta = meta;
        this.useDistinct = useDistinct;
    }

    /**
     * 解析函数
     */
    @Override
    public void visit(net.sf.jsqlparser.expression.Function function) {
        Function selectNode = FunctionFactory.getFunction(function.getName(), function.isDistinct());
        if (selectNode == null) {
            throw new SqlParseException("unknown function [" + function + "]");
        }
        
        ExpressionList expressionList = function.getParameters();

        if (expressionList != null && CollectionUtils.isNotEmpty(expressionList.getExpressions())) {
            List<SqlNode> params = new ArrayList<SqlNode>();
            for (Expression expression : expressionList.getExpressions()) {
                SelectNodeVisitor expressionVisitor = new SelectNodeVisitor(meta, useDistinct);
                expression.accept(expressionVisitor);

                SqlNode param = expressionVisitor.getSelectNode();
                if (param.getType() != SqlNodeType.TEXT && param.getType() != SqlNodeType.COLUMN) {
                    throw new SqlParseException("function param can only support column or text value");
                }
                params.add(param);
            }
            selectNode.setParams(params);
        }
        this.selectNode = selectNode;
    }

    @Override
    public void visit(LongValue longValue) {
        selectNode = new TextNode(longValue.getValue());
    }

    @Override
    public void visit(StringValue stringValue) {
        selectNode = new TextNode(stringValue.getValue());
    }

    @Override
    public void visit(Column tableColumn) {
        ColumnNode selectNode = new ColumnNode(tableColumn.getColumnName(), tableColumn.getTable().getName());

        FieldMeta fieldMeta = meta.getFiledMetas().get(tableColumn.getColumnName());
        if (fieldMeta == null) {
            throw new SqlParseException("cannot found available meta for column: " + tableColumn.getColumnName());
        }

        selectNode.setMeta(fieldMeta);
        this.selectNode = selectNode;
    }

    @Override
    public void visit(Parenthesis parenthesis) {
        if (useDistinct) {
            parenthesis.getExpression().accept(this);
        } else {
            super.visit(parenthesis);
        }
    }

    /**
     * 得到解析后的select节点
     * 
     * @return
     */
    public SqlNode getSelectNode() {
        return selectNode;
    }
}
